package administracion.managedBeans.pedidos;

import Entities.Interno;
import Entities.ItemProducto;
import Entities.Mozo;
import Entities.Reserva;
import ejb.ConsultaUniversalFacadeLocal;
import ejb.InternoFacadeLocal;
import ejb.ReservaFacadeLocal;
import ejb.soportes.Consulta;
import exceptions.ListaProductosPedidoVacia;
import java.io.Serializable;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import javax.annotation.PostConstruct;
import javax.ejb.EJB;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ManagedProperty;
import javax.faces.bean.ViewScoped;
import org.primefaces.context.RequestContext;
import org.primefaces.model.LazyDataModel;
import sesion.PermisoPagina;
import tablemodel.GeneralLazyModel;
import util.PageCodeGenerico;

/**
 * Clase que maneja lospedidos internos.
 */
@ManagedBean
@ViewScoped
public class PCPedidoInt extends PageCodeGenerico implements Serializable {

    @EJB
    private ReservaFacadeLocal reservaFacade;
    @EJB
    private ConsultaUniversalFacadeLocal consultaUniversalFacade;
    @EJB
    private InternoFacadeLocal entidadFacade;
    private LazyDataModel<Interno> listado;
    private Interno temporal;
    private Properties colsVisible;
    private Map<String, String> checksVisible;
    private List<String> selectedChecksVisible;
    private Accion accion = Accion.CREAR;
    private String mozo;
    private Map<String, String> mozos;
    private Reserva reserva;
    private final Double iva = 0.22;
    private Double total;
    private Double subTotal;
    private Double precioIva;
    private Date fechaHoy;
    @ManagedProperty("#{pCPedido}")
    private PCPedido pedidoGenerico;

    /**
     * Creates a new instance of InternoBean
     */
    public PCPedidoInt() {
        super();
        this.listado = new GeneralLazyModel<>(new Interno());
        this.temporal = new Interno();
        this.total = new Double(0);
        this.subTotal = new Double(0);
        this.precioIva = new Double(0);
        this.colsVisible = new Properties();
    }

    public Date getFechaHoy() {
        fechaHoy = new Date();
        return fechaHoy;
    }

    public void setFechaHoy(Date fechaHoy) {
        this.fechaHoy = fechaHoy;
    }

    public Double getSubTotal() {
        return subTotal;
    }

    public PCPedido getPedidoGenerico() {
        return pedidoGenerico;
    }

    public void setPedidoGenerico(PCPedido pedidoGenerico) {
        this.pedidoGenerico = pedidoGenerico;
    }

    public void setSubTotal(Double subTotal) {
        this.subTotal = subTotal;
    }

    /**
     * Devuelve el id de la tabla dependiendo si estoy en reservas o en el
     * listado
     */
    private String getIdFormData() {
        switch (accion) {
            case CREAR:
                return ":formdatapedido:pedido :formdatapedido:costo_pedido";
            case EDITAR:
                return ":tabs:formdatainterno:pedido  :tabs:formdatainterno:costo_pedido";
            default:
                return "";
        }
    }

    private String getIdFormTabla() {
        switch (accion) {
            case CREAR:
                return ":formTablareserva:tableModelreserva growldatapedido";
            case EDITAR:
                return ":tabs:formTablainterno:tableModelinterno growldatainterno";
            default:
                return "";
        }

    }

    public String getIdFormTablaFactu() {
        return ":tabs:formTablainterno:tableModelinterno growldata2interno";
    }

    public String getCierraDialogo() {
        switch (accion) {
            case CREAR:
                return "reserva";
            case EDITAR:
                return "interno";
            default:
                return "";
        }
    }

    private String formatearPrecio(double precio) {
        DecimalFormat df = new DecimalFormat("###,###.##");
        return df.format(precio);
    }

    public String devuelvePrecioItem(ItemProducto itemProducto) {
        return formatearPrecio(calculaPrecioItem(itemProducto));
    }

    public String devuelveTotalAPagar() {
        return formatearPrecio(totalAPagar());
    }

    /**
     * Recibe un itemProducto y establece el precio
     *
     * @param itemProducto
     * @return
     */
    private double calculaPrecioItem(ItemProducto itemProducto) {
        double resp = 0;
        if (itemProducto != null && itemProducto.getProducto() != null) {
            resp = itemProducto.getCantidad() * itemProducto.getProducto().getPrecio();
        }
        return resp;
    }

    /**
     * Calcula el total apagar por la persona
     *
     * @return
     */
    private double totalAPagar() {
        double resp = 0;
        if (this.getPedidoGenerico().getPedido() != null) {
            for (Iterator<ItemProducto> it = this.getPedidoGenerico().getPedido().iterator(); it.hasNext();) {
                ItemProducto item = it.next();
                if (item != null && item.getProducto() != null) {
                    resp += calculaPrecioItem(item);
                }
            }
        }
        return resp;
    }

    public void setearMesas(Reserva reserva) {
        reinicializarTemporal();
        temporal = temporal == null ? new Interno() : temporal;
        temporal.setListaMesas(reserva.getListaMesas());
        this.reserva = reserva;
    }

    public String getMozo() {
        return mozo;
    }

    public void setMozo(String mozo) {
        this.mozo = mozo;
    }

    /**
     * Obtiene la lista de mozos
     *
     * @return
     */
    public Map<String, String> getMozos() {
        mozos = new HashMap<>();
        Mozo f = new Mozo();
        Consulta c = new Consulta(f, Consulta.TipoUnion.OR);
        List<Mozo> fs = new ArrayList<>();
        try {
            fs = consultaUniversalFacade.consultar(c);
        } catch (Exception ex) {
        }
        for (Iterator<Mozo> it = fs.iterator(); it.hasNext();) {
            Mozo obj = it.next();
            mozos.put(obj.getNombreUsuario(), obj.getNombreUsuario());
        }
        return mozos;
    }

    public void setMozos(Map<String, String> mozos) {
        this.mozos = mozos;
    }

    public String devolverTituloDlg() {
        switch (this.accion) {
            case CREAR:
                return "Crear";
            case EDITAR:
                return "Editar";
            default:
                return "";
        }
    }

    public PermisoPagina consultarPermisos() {
        if (getMi_sesion() != null) {
            return getMi_sesion().consultarPermisos(Interno.class);
        } else {
            return new PermisoPagina();
        }
    }

    public String devolverTxtBtnCancelarDlg() {
        switch (this.accion) {
            case VER:
                return "Cerrar";
            default:
                return "Cancelar";
        }
    }

    public String devolverTxtLimpiarFormDlg() {
        switch (this.accion) {
            case EDITAR:
                return "Restablecer formulario";
            default:
                return "Limpiar formulario";
        }
    }

    public boolean esCrear() {
        return this.accion == Accion.CREAR;
    }

    public boolean esEditar() {
        return this.accion == Accion.EDITAR;
    }

    public boolean esVer() {
        return this.accion == Accion.VER;
    }

    /**
     * Reinicializo la lista de columas que puedo seleccionar.
     */
    @PostConstruct
    public void reinicializarChecks() {
        this.checksVisible = new HashMap<>();
        this.checksVisible.put("Id", "codigo");
        this.checksVisible.put("Fecha pedido", "fechaHora");
        this.checksVisible.put("Mozo", "mozo");
        this.checksVisible.put("Facturado", "facturado");
        this.selectedChecksVisible = new ArrayList<>();
        this.selectedChecksVisible.add("codigo");
        this.selectedChecksVisible.add("fechaHora");
        this.selectedChecksVisible.add("mozo");
        this.selectedChecksVisible.add("facturado");
    }

    /**
     * Seteo las columnas visibles. Segun selecciona el usuario en la pantalla
     */
    public void setearVisibles() {
        if (checksVisible != null && !checksVisible.isEmpty()) {
            for (Map.Entry<String, String> entry : checksVisible.entrySet()) {
                String valor = entry.getValue();
                boolean existe = false;
                if (selectedChecksVisible != null && !selectedChecksVisible.isEmpty()) {
                    for (Iterator<String> it = selectedChecksVisible.iterator(); it.hasNext();) {
                        String colSel = it.next();
                        if (colSel.trim().toLowerCase().equals(valor.trim().toLowerCase())) {
                            existe = true;
                            break;
                        }
                    }
                } else {
                    setearError("Debe seleccionar al menos una columna");
                    break;
                }
                this.colsVisible.put(valor, existe);
            }
        } else {
            setearError("Debe seleccionar al menos una columna");
        }
    }

    public LazyDataModel<Interno> getListado() {
        if (consultarPermisos().isVer()) {
            return listado;
        } else {
            return null;
        }
    }

    public void setListado(LazyDataModel<Interno> listado) {
        this.listado = listado;
    }

    public Interno getTemporal() {
        return temporal;
    }

    public void setTemporal(Interno temporal) {
        this.temporal = temporal;
    }

    public Map<String, String> getChecksVisible() {
        return checksVisible;
    }

    public void setChecksVisible(Map<String, String> checksVisible) {
        this.checksVisible = checksVisible;
    }

    public List<String> getSelectedChecksVisible() {
        return selectedChecksVisible;
    }

    public void setSelectedChecksVisible(List<String> selectedChecksVisible) {
        this.selectedChecksVisible = selectedChecksVisible;
    }

    /**
     * Reinciialiso el tempodal
     */
    public void reinicializarTemporal() {
        this.temporal = new Interno();
        this.mozo = null;
        this.getPedidoGenerico().setPedido(null);
        this.accion = Accion.CREAR;
        this.total = new Double(0);
        this.subTotal = new Double(0);
        this.precioIva = new Double(0);
        this.pedidoGenerico.setGetIdFormTabla(this.getIdFormTabla());
        this.pedidoGenerico.setIdInternoData(this.getIdFormData());

    }

    /**
     * Estabelece el pedido interno con el cual voy a trabajar dependiendo si
     * estoy en la funcion de crear o editar.
     *
     * @param objeto
     * @param isEditar
     */
    public void establecerTemporal(Interno objeto, boolean isEditar) {
        this.accion = (isEditar) ? Accion.EDITAR : Accion.VER;
        pedidoGenerico.setGetIdFormTabla(this.getIdFormTabla());
        pedidoGenerico.setIdInternoData(this.getIdFormData());
        this.temporal = (objeto == null) ? new Interno() : objeto;
        if (temporal != null) {
            this.mozo = this.temporal.getMozo().getNombreUsuario();
            this.getPedidoGenerico().setPedido(this.temporal.getListaItemsProductos());
        }
    }

    public void reinicializarColsVisible() {
        this.colsVisible.clear();
    }

    /**
     *
     * @param col Sin tildes ni espacios y en minúsculas
     * @param visible
     */
    public void establecerColVisible(String col, boolean visible) {
        this.colsVisible.put(col, visible);
    }

    /**
     *
     * @param col Sin tildes ni espacios y en minúsculas
     * @return
     */
    public boolean getColVisible(String col) {
        boolean resp = true;
        if (this.colsVisible.get(col) != null) {
            try {
                resp = (boolean) this.colsVisible.get(col);
            } catch (Exception e) {
            }
        }
        return resp;
    }

    /**
     * Elimina un pedido
     */
    public void eliminar() {
        if (consultarPermisos().isBaja()) {
            if (this.temporal != null) {
                try {
                    entidadFacade.eliminar(this.temporal);
                    setearInfo("Operación finalizada correctamente.");
                } catch (Exception e) {
                    setearError(e);
                }
            } else {
                setearInfo("Nada que eliminar.");
            }
        } else {
            setearError("No tiene permisos suficientes para ejecutar esta acción");
        }
    }

    public String parseaHora(Date hora) {
        String resp = "";
        if (hora != null) {
            SimpleDateFormat s = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss");
            resp = s.format(hora);
        }
        return resp;
    }

    /**
     * Guarda un pedido y devuelve un boolean si fue exitoso o no
     *
     * @param mi_param
     * @return G
     */
    public boolean guardar(String mi_param) {
        if (mozo != null) {
            Mozo f = new Mozo();
            Consulta c = new Consulta(f, Consulta.TipoUnion.OR);
            List<Mozo> fs = new ArrayList<>();
            try {
                fs = consultaUniversalFacade.consultar(c);
            } catch (Exception ex) {
            }
            for (Iterator<Mozo> it = fs.iterator(); it.hasNext();) {
                Mozo obj = it.next();
                if (obj.getNombreUsuario() == null ? mozo == null : obj.getNombreUsuario().equals(mozo)) {
                    temporal.setMozo(obj);
                    break;
                }
            }
        }
        temporal.setListaItemsProductos(this.getPedidoGenerico().getPedido());
        switch (this.accion) {
            case CREAR:
                temporal.setFechaHora(new Date());
                return crear(mi_param);
            case EDITAR:
                return modificar(mi_param);
            default:
                return false;
        }
    }

    /**
     * Clase que modifica un pedido devuelve un boleano
     *
     * @param mi_param
     * @return
     */
    private boolean modificar(String mi_param) {
        if (consultarPermisos().isModificacion()) {
            try {
                String codigo = String.valueOf(this.temporal.getId());
//                this.temporal.setFacturado(true);
                entidadFacade.editar(this.temporal);
                setearInfo("Modificación exitosa " + "de pedido " + mi_param + " con código: " + codigo);
                RequestContext.getCurrentInstance().addCallbackParam("correcto", true);
                RequestContext.getCurrentInstance().addCallbackParam("param", mi_param);
                return true;
            } catch (Exception e) {
                setearError(e);
                RequestContext.getCurrentInstance().addCallbackParam("correcto", false);
                RequestContext.getCurrentInstance().addCallbackParam("param", mi_param);
                return false;
            }
        } else {
            return false;
        }
    }

    /**
     * Funcion que dado un pedido establece la factura para que se pueda ver.
     *
     * @param objeto
     */
    public void imprimirFactura(Interno objeto) {
        this.establecerTemporal(objeto, true);
            this.total = new Double(0);
            this.subTotal = new Double(0);
            this.precioIva = new Double(0);
            for (ItemProducto it : this.temporal.getListaItemsProductos()) {
                Double precio = it.getCantidad() * it.getPrecioVigente();
                total = total + precio;
            }
            Double totalextra = total;
            precioIva = (totalextra * 1.22) - totalextra;
            subTotal = total - precioIva;
    }

    /**
     * Funcion que establece la factura en estado facturado la impresionde la
     * misma.
     *
     * @param mi_param
     * @return
     */
    public boolean facturar(String mi_param) {
        if (consultarPermisos().isFacturar()) {
            try {
                String codigo = String.valueOf(this.temporal.getId());
                this.temporal.setFacturado(true);
                entidadFacade.editar(this.temporal);
                setearInfo("Impresión exitosa " + "de pedido" + mi_param + " con código: " + codigo);
                RequestContext.getCurrentInstance().addCallbackParam("correcto", true);
                RequestContext.getCurrentInstance().addCallbackParam("param", mi_param);
                return true;
            } catch (Exception e) {
                setearError(e);
                RequestContext.getCurrentInstance().addCallbackParam("correcto", false);
                RequestContext.getCurrentInstance().addCallbackParam("param", mi_param);
                return false;
            }
        } else {
            return false;
        }
    }

    /**
     * Funcion que recibe item de la lista y establece si es editable
     *
     * @param item
     * @return
     */
    public Boolean esEditable(Interno item) {
        Boolean resu;
        if (item.getFacturado() == true) {
            resu = false;
        } else {
            resu = true;
        }
        return resu;

    }

    /**
     * Funcion que valida que haya ingresado al menos un producto al pedido
     *
     * @throws ListaProductosPedidoVacia
     */
    private void validarLista() throws ListaProductosPedidoVacia {
        if (this.temporal.getListaItemsProductos() == null || this.temporal.getListaItemsProductos().isEmpty()) {
            throw new ListaProductosPedidoVacia("Debe seleccionar al menos un producto para su menú");
        } else {
            List<ItemProducto> pedido = this.temporal.getListaItemsProductos();
            int cantidad = 0;
            for (Iterator<ItemProducto> it = pedido.iterator(); it.hasNext();) {
                ItemProducto itemProducto = it.next();
                if (itemProducto != null) {
                    cantidad += itemProducto.getCantidad();
                }
            }
            if (cantidad == 0) {
                throw new ListaProductosPedidoVacia("Debe seleccionar al menos un producto para su menú");
            }
        }
    }

    /**
     * Funcion para crear pedido.
     *
     * @param mi_param
     * @return
     */
    private boolean crear(String mi_param) {
        if (consultarPermisos().isAlta()) {
            try {
                validarLista();
                entidadFacade.crear(this.temporal);
                reservaFacade.eliminar(reserva);
                setearInfo("Se ha creado " + "exitosamente un nuevo pedido " + mi_param);
                RequestContext.getCurrentInstance().addCallbackParam("correcto", true);
                RequestContext.getCurrentInstance().addCallbackParam("param", mi_param);
                return true;
            } catch (Exception e) {
                setearError(e);
                RequestContext.getCurrentInstance().addCallbackParam("correcto", false);
                RequestContext.getCurrentInstance().addCallbackParam("param", mi_param);
                return false;
            }
        } else {
            return false;
        }
    }

    public enum Accion {

        CREAR, EDITAR, VER;
    }

    public Double getTotal() {
        return total;
    }

    public void setTotal(Double total) {
        this.total = total;
    }

    public Double getPrecioIva() {
        return precioIva;
    }

    public void setPrecioIva(Double precioIva) {
        this.precioIva = precioIva;
    }
}
